package com.xbongbong.paas.script.controller;


import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.domain.entity.PaasMenuEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.MenuTypeEnum;
import com.xbongbong.paas.help.menu.InitJxcMenuHelp;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasMenuModel;
import com.xbongbong.paas.pojo.dto.FixDataJobDTO;
import com.xbongbong.paas.pojo.dto.FormEntityAddDTO;
import com.xbongbong.paas.service.PaasFormService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.menu.enums.JXCMenuEnum;
import com.xbongbong.pro.form.pojo.dto.FormAddBatchDTO;
import com.xbongbong.pro.form.pojo.vo.FormAddBatchVO;
import com.xbongbong.pro.menu.pojo.dto.MenuInitDTO;
import com.xbongbong.pro.script.pojo.dto.ProductDTO;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.domain.entity.StockFlowBillEntity;
import com.xbongbong.saas.domain.entity.StockSurplusRecordEntity;
import com.xbongbong.saas.domain.entity.WarehouseOristockEntity;
import com.xbongbong.saas.domain.entity.WarehouseOristockProductEntity;
import com.xbongbong.saas.domain.entity.ext.InstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.WarehouseEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.StockTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractOutstockEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.PurchaseInstockEnum;
import com.xbongbong.saas.enums.business.RefundInstockEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseOutstockEnum;
import com.xbongbong.saas.enums.business.WarehouseEnum;
import com.xbongbong.saas.enums.business.WorkOrderOutstockEnum;
import com.xbongbong.saas.model.InstockModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductWarehouseModel;
import com.xbongbong.saas.model.StockFlowBillModel;
import com.xbongbong.saas.model.StockSurplusRecordModel;
import com.xbongbong.saas.model.WarehouseModel;
import com.xbongbong.saas.model.WarehouseOristockModel;
import com.xbongbong.saas.model.WarehouseOristockProductModel;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.model.CompanyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lee
 * @version v1.0
 * @date 2020/04/12 15:15
 * @since v1.0
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/script/stockBill")
public class ProductStockBillScriptController {
    private static final Logger LOG = LoggerFactory.getLogger(ProductStockBillScriptController.class);

    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private PaasMenuModel paasMenuModel;
    @Resource
    private InitJxcMenuHelp initJxcMenuHelp;
    @Resource
    private PaasFormService paasFormService;
    @Resource
    private ProductModel productModel;
    @Resource
    private WarehouseModel warehouseModel;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private InstockModel instockModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private OutstockModel outstockModel;
    @Resource
    private WarehouseOristockModel warehouseOristockModel;
    @Resource
    private WarehouseOristockProductModel warehouseOristockProductModel;
    @Resource
    private ProductWarehouseModel productWarehouseModel;
    @Resource
    private StockSurplusRecordModel stockSurplusRecordModel;
    @Resource
    private StockFlowBillModel stockFlowBillModel;

    @RequestMapping(value = "/addStockBillMenu", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @Transactional(rollbackFor = Exception.class)
    public String addStockMenu(@RequestBody @Valid ProductDTO productDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(productDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        long start = DateTimeUtil.getInt();
        String userId = productDTO.getUserId();
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<String> corpidList;
        param.put("del", 0);
        if (CollectionsUtil.isNotEmpty(productDTO.getCorpidList())) {
            corpidList = productDTO.getCorpidList();
            param.put("corpidIn", corpidList);
        } else {
            corpidList = companyModel.getCorpidList();
        }
        int total = corpidList.size();
        int pageSize = 1000;
        int totalPage = ((total-1) / pageSize) + 1;
        for (int i = 0; i < total; i += pageSize) {
            LOG.warn("addStockBillMenu:" + i + "/" + totalPage);
            param.clear();
            param.put("del", 0);
            param.put("start", i);
            param.put("pageNum", pageSize);
            param.put("columns", "corpid");
            param.put("corpidIn", corpidList);
            List<CompanyEntity> companyEntityList = companyModel.findEntitys(param);
            if (Objects.isNull(companyEntityList) || companyEntityList.isEmpty()) {
                continue;
            }
            List<String> corpids = new ArrayList<>(pageSize);
            companyEntityList.forEach(item -> {
                corpids.add(item.getCorpid());
            });
            Map<String, Object> appParam = new HashMap<>();
            appParam.put("del", 0);
            appParam.put("corpidIn", corpids);
            appParam.put("alias", XbbRefTypeEnum.JXC.getAlias());
            List<PaasAppEntity> entitys = paasAppModel.findEntitys(appParam);
            if (Objects.isNull(entitys) || entitys.isEmpty()) {
                continue;
            }
            Long now = DateTimeUtil.getInt();

            List<Long> appIds = new ArrayList<>(entitys.size());
            entitys.forEach(item -> appIds.add(item.getId()));
            Map<String, Object> menuParam = new HashMap<>();
            menuParam.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            menuParam.put("appIdList", appIds);
            menuParam.put("parentId", 0);
            menuParam.put("alias", XbbRefTypeEnum.INVENTORY_MANAGEMENT.getAlias());
            List<PaasMenuEntity> menuEntities = paasMenuModel.findEntitys(menuParam);
            Map<Long, Long> stockMap = new HashMap<>(menuEntities.size());
            menuEntities.forEach(item -> stockMap.put(item.getAppId(), item.getId()));
            menuParam.remove("parentId");
            menuParam.remove("alias");
            menuParam.put("parentIdIn", stockMap.values());
            List<PaasMenuEntity> secondStockMenuList = paasMenuModel.findEntitys(menuParam);
            Map<Long, Integer> stockBillSortMap = new HashMap<>(menuEntities.size());
            Set<Long> hasStockBillMenuSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (PaasMenuEntity menuEntity : secondStockMenuList) {
                Long parentId = menuEntity.getParentId();
                Integer sort = menuEntity.getSort() == null ? 1 : menuEntity.getSort();
                if (Objects.equals(XbbRefTypeEnum.STOCK_FLOW_BILL.getAlias(), menuEntity.getAlias()) || Objects.equals(XbbRefTypeEnum.STOCK_STANDING_BOOK.getAlias(), menuEntity.getAlias())) {
                    hasStockBillMenuSet.add(parentId);
                    continue;
                }
                if (stockBillSortMap.containsKey(parentId)) {
                    if (sort > stockBillSortMap.get(parentId)) {
                        stockBillSortMap.put(parentId, sort);
                    }
                } else {
                    stockBillSortMap.put(parentId, sort);
                }
            }

            //拿到1000家公司的app
            for (int j = 0; j < menuEntities.size(); j ++) {
                PaasMenuEntity item = menuEntities.get(j);
                // 生成过采购入库单菜单的就当已经生成过拆分菜单了
                if (hasStockBillMenuSet.contains(item.getId())) {
                    LOG.warn("corpid:" + item.getCorpid() + ",page:" + i + "/" + totalPage + "app page:" + j + "/" + entitys.size() + "has cut");
                    continue;
                }
                List<JXCMenuEnum> jxcMenuEnums = Arrays.asList(JXCMenuEnum.STOCK_FLOW_BILL, JXCMenuEnum.STOCK_STANDING_BOOK);
                List<PaasMenuEntity> formAddMenuList = new ArrayList<>();
                for (JXCMenuEnum jxcMenuEnum : jxcMenuEnums) {
                    PaasMenuEntity paasMenuEntity = new PaasMenuEntity();
                    paasMenuEntity.setCorpid(item.getCorpid());
                    paasMenuEntity.setAppId(item.getAppId());
                    paasMenuEntity.setParentId(item.getId());
                    paasMenuEntity.setSort(stockBillSortMap.get(item.getId()));
                    stockBillSortMap.put(item.getId(), paasMenuEntity.getSort() + 1);
                    paasMenuEntity.setCreatorId(userId);
                    paasMenuEntity.setAlias(jxcMenuEnum.getAlias());
                    paasMenuEntity.setColor(jxcMenuEnum.getAccessLinkEnum().getColor());
                    paasMenuEntity.setIcon(jxcMenuEnum.getAccessLinkEnum().getIcon());
                    paasMenuEntity.setSaasMark(1);
                    paasMenuEntity.setUrl(jxcMenuEnum.getAccessLinkEnum().getUrl());
                    paasMenuEntity.setMobileUrl(jxcMenuEnum.getAccessLinkEnum().getMobileUrl());
                    paasMenuEntity.setType(MenuTypeEnum.FORM.getType());
                    paasMenuEntity.setEnable(1);
                    paasMenuEntity.setName(jxcMenuEnum.getName());
                    paasMenuEntity.setCreatorId(userId);
                    paasMenuEntity.setAddTime(now);
                    paasMenuEntity.setUpdateTime(now);
                    formAddMenuList.add(paasMenuEntity);
                }
                List<PaasMenuEntity> formMenuList = paasMenuModel.insertBatch(formAddMenuList);
                // 插入菜单对应的表单
                FormAddBatchDTO formAddBatchDTO = new FormAddBatchDTO();
                BeanUtil.copyProperties(productDTO, formAddBatchDTO);
                List<FormEntityAddDTO> formList = new ArrayList<>();
                initJxcMenuHelp.getFormList(formList, formMenuList);
                formAddBatchDTO.setFormList(formList);
                FormAddBatchVO formAddBatchVO = paasFormService.addBatch(formAddBatchDTO);
                if (Objects.isNull(formAddBatchVO)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                MenuInitDTO menuInitDTO = new MenuInitDTO();
                BeanUtil.copyProperties(productDTO, menuInitDTO);
                // 插入表单对应的字段解释
                initJxcMenuHelp.formExplainAddBatch(menuInitDTO, formAddBatchVO);
            }
        }
        LOG.warn("consume:" + (DateTimeUtil.getInt() - start));
        LOG.warn("addStockMenu over");
        return "success";
    }

    /**
     * 获取线上错误数据
     * @param fixDataJobDTO
     * @param br
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/getWrongStock", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String getWrongStock(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        List<String> corpidList = productModel.getCorpidList();
        LOG.warn("getWrongStock begin");
        List<String> wrongCorpIdList = new ArrayList<>();
        int wrongProductStock = 0;
        for (String corpid : corpidList) {
            Long idGte = 0L;
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            List<WarehouseEntityExt> warehouseEntityExtList = warehouseModel.findEntitys(param);
            List<Long> warehouseIdList = new ArrayList<>();
            warehouseEntityExtList.forEach(item -> warehouseIdList.add(item.getId()));
            warehouseIdList.add(-1L);
            while (true) {
                param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(StringConstant.CORPID, corpid);
                param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
                if (Objects.nonNull(fixDataJobDTO.getDataIdList()) && !fixDataJobDTO.getDataIdList().isEmpty()) {
                    param.put("idIn", fixDataJobDTO.getDataIdList());
                }
                param.put("dataParentIdGte", 0L);
                param.put("idGte", idGte);
                param.put("pageSize", 1000);
                param.put("orderByStr", "id asc");
                List<ProductEntityExt> productEntityExtList = productModel.findEntitys(param);
                if (productEntityExtList.isEmpty()) {
                    if (idGte <= 0L) {
                        LOG.warn(JSONObject.toJSONString(param));
                        return "When I put a question mark, it is not that I have a problem, but I think you have a problem.";
                    }
                    break;
                }
                LOG.warn("idGte:" + idGte);
                idGte = productEntityExtList.get(productEntityExtList.size() - 1).getId();
                List<Long> productIdList = new ArrayList<>();
                productEntityExtList.forEach(item -> productIdList.add(item.getId()));
                //入库
                Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                map.put("corpid", corpid);
                map.put("productIdIn", productIdList);
                map.put("warehouseIdIn", warehouseIdList);
                map.put("del", 0);
                List<InstockProductEntity> instockProductEntityList = instockProductModel.findEntitys(map);
                List<Long> idList = new ArrayList<>();
                if (!instockProductEntityList.isEmpty()) {
                    List<Long> instockIdList = new ArrayList<>();
                    instockProductEntityList.forEach(item -> instockIdList.add(item.getIntoWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", instockIdList);
                    filterMap.put("del", 0);
                    idList = instockModel.findIds(filterMap);
                }
                Map<Long, Double> skuStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String, Double> productWarehouseStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (InstockProductEntity entity : instockProductEntityList) {
                    if (!idList.contains(entity.getIntoWarehouseId())) {
                        continue;
                    }
                    //sku
                    Double skuStock = skuStockMap.getOrDefault(entity.getProductId(), 0D);
                    skuStock = Arith.add(skuStock, entity.getProductNum());
                    skuStockMap.put(entity.getProductId(), skuStock);
                    //productWarehouse
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key, 0D);
                    productWarehouseStock = Arith.add(productWarehouseStock, entity.getProductNum());
                    productWarehouseStockMap.put(key, productWarehouseStock);
                }
                //出库
                List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.findEntitys(map);
                idList = new ArrayList<>();
                if (!outstockProductEntityList.isEmpty()) {
                    List<Long> outstockIdList = new ArrayList<>();
                    outstockProductEntityList.forEach(item -> outstockIdList.add(item.getOutWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", outstockIdList);
                    filterMap.put("del", 0);
                    idList = outstockModel.findIds(filterMap);
                }
                for (OutstockProductEntity entity : outstockProductEntityList) {
                    if (!idList.contains(entity.getOutWarehouseId())) {
                        continue;
                    }
                    //sku
                    Double skuStock = skuStockMap.getOrDefault(entity.getProductId(), 0D);
                    skuStock = Arith.sub(skuStock, entity.getProductNum());
                    skuStockMap.put(entity.getProductId(), skuStock);
                    //productWarehouse
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key, 0D);
                    productWarehouseStock = Arith.sub(productWarehouseStock, entity.getProductNum());
                    productWarehouseStockMap.put(key, productWarehouseStock);
                }
                // 期初
                param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(StringConstant.CORPID, corpid);
                param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
                List<WarehouseOristockEntity> warehouseOristockEntityList = warehouseOristockModel.findEntitys(param);
                List<Long> oriWarehouseIdList = new ArrayList<>();
                Map<Long, Long> oriWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                warehouseOristockEntityList.forEach(item -> {
                    oriWarehouseMap.put(item.getId().longValue(), item.getWarehouseId());
                    oriWarehouseIdList.add(item.getWarehouseId());
                });
                param.put("oriStockIdIn", oriWarehouseMap.keySet());
                param.put("productIdIn", productIdList);
                List<WarehouseOristockProductEntity> warehouseOristockProductEntityList = warehouseOristockProductModel.findEntitys(param);
                for (WarehouseOristockProductEntity warehouseOristockProductEntity : warehouseOristockProductEntityList) {
                    if (oriWarehouseMap.containsKey(warehouseOristockProductEntity.getOristockId().longValue())) {
                        Long warehouseId = oriWarehouseMap.get(warehouseOristockProductEntity.getOristockId().longValue());
                        // 分仓库存
                        String key = warehouseOristockProductEntity.getProductId() + "_" + warehouseId;
                        Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key, 0D);
                        productWarehouseStock = Arith.add(productWarehouseStock, warehouseOristockProductEntity.getOristockNum());
                        productWarehouseStockMap.put(key, productWarehouseStock);
                        // sku库存
                        Double skuStock = skuStockMap.getOrDefault(warehouseOristockProductEntity.getProductId(), 0D);
                        skuStock = Arith.add(skuStock, warehouseOristockProductEntity.getOristockNum());
                        skuStockMap.put(warehouseOristockProductEntity.getProductId(), skuStock);
                    }
                }
                //分仓
                param.clear();
                param.put("corpid", corpid);
                param.put("productIdIn", productIdList);
                param.put("warehouseChecked", 1);
                param.put("del", 0);
                param.put("columns", "corpid,id,product_id,warehouse_id,cost,ori_num");
                List<ProductWarehouseEntity> productWarehouseEntityList = productWarehouseModel.findEntitysWithWarehouseChecked(param,1);
                List<ProductWarehouseEntity> updateProductWareouseList = new ArrayList<>();
                Iterator<ProductWarehouseEntity> iterator = productWarehouseEntityList.iterator();
                //由于可能有老期初，同时又有全仓记录，先循环分仓记录，兼容老期初，再更新全仓记录
                while (iterator.hasNext()) {
                    ProductWarehouseEntity entity = iterator.next();
                    if (!Objects.equals(entity.getWarehouseId(), 0L)) {
                        String key = entity.getProductId() + "_" + entity.getWarehouseId();
                        //老期初 有新期初时不使用老期初
                        if (entity.getOriNum() > 0 && !oriWarehouseIdList.contains(entity.getWarehouseId())) {
                            // 分仓数据
                            Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key, 0D);
                            productWarehouseStock = Arith.add(productWarehouseStock, entity.getOriNum());
                            productWarehouseStockMap.put(key, productWarehouseStock);
                            // sku数据
                            Double skuStock = skuStockMap.getOrDefault(entity.getProductId(), 0D);
                            skuStock = Arith.add(skuStock, entity.getOriNum());
                            skuStockMap.put(entity.getProductId(), skuStock);
                        }
                        if (productWarehouseStockMap.containsKey(key)) {
                            if (Objects.equals(entity.getNum(), productWarehouseStockMap.get(key))) {
                                iterator.remove();
                                continue;
                            }
                            entity.setNum(productWarehouseStockMap.get(key));
                            productWarehouseStockMap.remove(key);
                        } else {
                            entity.setNum(0D);
                        }
                        updateProductWareouseList.add(entity);
                        iterator.remove();
                    }
                }
                //全仓记录
                for (ProductWarehouseEntity entity : productWarehouseEntityList) {
                    if (Objects.equals(entity.getWarehouseId(), 0L)) {
                        if (Objects.equals(entity.getNum(), skuStockMap.get(entity.getProductId()))) {
                            continue;
                        }
                        entity.setNum(skuStockMap.getOrDefault(entity.getProductId(), 0D));
                        updateProductWareouseList.add(entity);
                    }
                }
                if (!updateProductWareouseList.isEmpty()) {
                    wrongCorpIdList.add(corpid);
                    wrongProductStock += updateProductWareouseList.size();
                } else {
                    LOG.warn("no product warehouse update");
                }
            }
        }
        LOG.warn("corpIdList:" + String.join(",", wrongCorpIdList));
        LOG.warn("wrongProductStock:" + wrongProductStock);
        LOG.warn("fixAllStock over");
        return "success";
    }

    /**
     * 修复某个公司(某个产品)的所有库存信息:sku、productWarehouse
     * @param fixDataJobDTO
     * @param br
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/fixAllStock", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String fixAllStock(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (Objects.isNull(corpidList)) {
            corpidList = productModel.getCorpidList();
        }
        LOG.warn("fixAllStock begin");
        for (String corpid : corpidList) {
            Long idGte = 0L;
            Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID,corpid);
            param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
            List<WarehouseEntityExt> warehouseEntityExtList = warehouseModel.findEntitys(param);
            Map<Long,String>  warehouseNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> warehouseIdList = new ArrayList<>();
            warehouseEntityExtList.forEach(item -> {
                warehouseNameMap.put(item.getId(), item.getData().getString(WarehouseEnum.WAREHOUSE_NAME.getAttr()));
                warehouseIdList.add(item.getId());
            });
            warehouseIdList.add(-1L);
            while (true) {
                param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                if (Objects.nonNull(fixDataJobDTO.getDataIdList()) && !fixDataJobDTO.getDataIdList().isEmpty()) {
                    param.put("idIn",fixDataJobDTO.getDataIdList());
                }
                param.put("dataParentIdGte",0L);
                param.put("idGte",idGte);
                param.put("pageSize",1000);
                param.put("orderByStr","id asc");
                List<ProductEntityExt> productEntityExtList = productModel.findEntitys(param);
                if (productEntityExtList.isEmpty()) {
                    if (idGte <= 0L){
                        LOG.warn(JSONObject.toJSONString(param));
                        return "When I put a question mark, it is not that I have a problem, but I think you have a problem.";
                    }
                    break;
                }
                LOG.warn("idGte:" + idGte);
                idGte = productEntityExtList.get(productEntityExtList.size()-1).getId();
                Map<Long, Long> parentProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                List<Long> productIdList = new ArrayList<>();
                productEntityExtList.forEach(item -> {
                    productIdList.add(item.getId());
                    parentProductMap.put(item.getId(), item.getData().getLong(ProductEnum.PARENT_ID.getAttr()));
                });
                //入库
                Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                map.put("corpid",corpid);
                map.put("productIdIn",productIdList);
                map.put("warehouseIdIn",warehouseIdList);
                map.put("del",0);
                List<InstockProductEntity> instockProductEntityList = instockProductModel.findEntitys(map);
                List<Long> idList = new ArrayList<>();
                if (!instockProductEntityList.isEmpty()) {
                    List<Long> instockIdList = new ArrayList<>();
                    instockProductEntityList.forEach(item -> instockIdList.add(item.getIntoWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", instockIdList);
                    filterMap.put("del", 0);
                    idList = instockModel.findIds(filterMap);
                }
                Map<Long,Double> skuStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Double>  productWarehouseStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Double>  productWarehouseCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (InstockProductEntity entity : instockProductEntityList){
                    if (!idList.contains(entity.getIntoWarehouseId())){
                        continue;
                    }
                    //sku
                    Double skuStock = skuStockMap.getOrDefault(entity.getProductId(),0D);
                    skuStock = Arith.add(skuStock,entity.getProductNum());
                    skuStockMap.put(entity.getProductId(),skuStock);
                    //productWarehouse
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                    productWarehouseStock = Arith.add(productWarehouseStock,entity.getProductNum());
                    productWarehouseStockMap.put(key,productWarehouseStock);
                    // 分仓总成本
                    Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                    productWarehouseCost = Arith.add(productWarehouseCost,Arith.mul(entity.getProductNum(), entity.getCost()));
                    productWarehouseCostMap.put(key,productWarehouseCost);
                }
                //出库
                List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.findEntitys(map);
                if (!outstockProductEntityList.isEmpty()) {
                    List<Long> outstockIdList = new ArrayList<>();
                    outstockProductEntityList.forEach(item -> outstockIdList.add(item.getOutWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", outstockIdList);
                    filterMap.put("del", 0);
                    idList = outstockModel.findIds(filterMap);
                }
                for (OutstockProductEntity entity : outstockProductEntityList){
                    if (!idList.contains(entity.getOutWarehouseId())){
                        continue;
                    }
                    //sku
                    Double skuStock = skuStockMap.getOrDefault(entity.getProductId(),0D);
                    skuStock = Arith.sub(skuStock,entity.getProductNum());
                    skuStockMap.put(entity.getProductId(),skuStock);
                    //productWarehouse
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                    productWarehouseStock = Arith.sub(productWarehouseStock,entity.getProductNum());
                    productWarehouseStockMap.put(key,productWarehouseStock);
                    // 分仓总成本
                    Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                    productWarehouseCost = Arith.sub(productWarehouseCost,Arith.mul(entity.getProductNum(), entity.getCost()));
                    productWarehouseCostMap.put(key,productWarehouseCost);
                }
                param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                List<WarehouseOristockEntity> warehouseOristockEntityList = warehouseOristockModel.findEntitys(param);
                List<Long> oriWarehouseIdList = new ArrayList<>();
                Map<Long,Long> oriWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                warehouseOristockEntityList.forEach(item -> {
                    oriWarehouseMap.put(item.getId().longValue(),item.getWarehouseId());
                    oriWarehouseIdList.add(item.getWarehouseId());
                });
                param.put("oriStockIdIn",oriWarehouseMap.keySet());
                param.put("productIdIn",productIdList);
                List<WarehouseOristockProductEntity> warehouseOristockProductEntityList = warehouseOristockProductModel.findEntitys(param);
                for (WarehouseOristockProductEntity warehouseOristockProductEntity : warehouseOristockProductEntityList) {
                    if (oriWarehouseMap.containsKey(warehouseOristockProductEntity.getOristockId().longValue())){
                        Long warehouseId = oriWarehouseMap.get(warehouseOristockProductEntity.getOristockId().longValue());
                        // 分仓库存
                        String key = warehouseOristockProductEntity.getProductId() + "_" + warehouseId;
                        Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                        productWarehouseStock = Arith.add(productWarehouseStock,warehouseOristockProductEntity.getOristockNum());
                        productWarehouseStockMap.put(key,productWarehouseStock);
                        // sku库存
                        Double skuStock = skuStockMap.getOrDefault(warehouseOristockProductEntity.getProductId(),0D);
                        skuStock = Arith.add(skuStock,warehouseOristockProductEntity.getOristockNum());
                        skuStockMap.put(warehouseOristockProductEntity.getProductId(),skuStock);
                    }
                }
                //分仓
                param.clear();
                param.put("corpid",corpid);
                param.put("productIdIn",productIdList);
                param.put("warehouseChecked",1);
                param.put("del",0);
                List<ProductWarehouseEntity> productWarehouseEntityList = productWarehouseModel.findEntitysWithWarehouseChecked(param,1);
                List<ProductWarehouseEntity> updateProductWareouseList = new ArrayList<>();
                Iterator<ProductWarehouseEntity> iterator = productWarehouseEntityList.iterator();
                // 重复分仓记录需要删除
                Set<String> warehouseKeySet = new HashSet<>(productWarehouseEntityList.size());
                //由于可能有老期初，同时又有全仓记录，先循环分仓记录，兼容老期初，再更新全仓记录
                while (iterator.hasNext()) {
                    ProductWarehouseEntity entity = iterator.next();
                    if (warehouseKeySet.contains(entity.getWarehouseKey())) {
                        entity.setDel(DelEnum.DELETE.getDel());
                        updateProductWareouseList.add(entity);
                        iterator.remove();
                        continue;
                    } else {
                        warehouseKeySet.add(entity.getWarehouseKey());
                    }
                    if (!Objects.equals(entity.getWarehouseId(),0L)){
                        String key = entity.getProductId() + "_" + entity.getWarehouseId();
                        if (entity.getOriNum() > 0 && !oriWarehouseIdList.contains(entity.getWarehouseId())) {
                            //老期初
                            Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                            productWarehouseStock = Arith.add(productWarehouseStock,entity.getOriNum());
                            productWarehouseStockMap.put(key,productWarehouseStock);

                            Double skuStock = skuStockMap.getOrDefault(entity.getProductId(),0D);
                            skuStock = Arith.add(skuStock,entity.getOriNum());
                            skuStockMap.put(entity.getProductId(),skuStock);
                        }
                        if (productWarehouseStockMap.containsKey(key)){
                            if (Objects.equals(entity.getNum(), productWarehouseStockMap.get(key))) {
                                iterator.remove();
                                productWarehouseStockMap.remove(key);
                                continue;
                            }
                            entity.setNum(productWarehouseStockMap.get(key));
                            productWarehouseStockMap.remove(key);
                        }else {
                            if (Objects.equals(entity.getNum(), 0D)) {
                                iterator.remove();
                                continue;
                            } else {
                                entity.setNum(0D);
                            }
                        }
                        updateProductWareouseList.add(entity);
                        iterator.remove();
                    }
                }
                //全仓记录
                for (ProductWarehouseEntity entity : productWarehouseEntityList){
                    if (Objects.equals(entity.getWarehouseId(),0L)){
                        if (Objects.equals(entity.getNum(), skuStockMap.get(entity.getProductId()))) {
                            continue;
                        }
                        entity.setNum(skuStockMap.getOrDefault(entity.getProductId(),0D));
                        updateProductWareouseList.add(entity);
                    }
                }
                if (!updateProductWareouseList.isEmpty()){
                    productWarehouseModel.updateStockBatch(updateProductWareouseList,corpid);
                } else {
                    LOG.warn("no product warehouse update");
                }
                if (!productWarehouseStockMap.isEmpty()){
                    List<ProductWarehouseEntity> insertList = new ArrayList<>();
                    for (Map.Entry<String, Double> entry : productWarehouseStockMap.entrySet()) {
                        String warehouseKey = entry.getKey();
                        Double num = entry.getValue();
                        String[] args = warehouseKey.split("_");
                        Long warehouseId = Long.valueOf(args[1]);
                        Long productId = Long.valueOf(args[0]);
                        // 这个判断应该没有用
                        if (Objects.equals(warehouseId, 0L)) {
                            continue;
                        }
                        ProductWarehouseEntity productWarehouseEntity = new ProductWarehouseEntity();
                        productWarehouseEntity.setCorpid(corpid);
                        productWarehouseEntity.setWarehouseId(warehouseId);
                        productWarehouseEntity.setParentId(parentProductMap.get(productId));
                        productWarehouseEntity.setProductId(productId);
                        productWarehouseEntity.setWarehouseName(warehouseNameMap.getOrDefault(warehouseId, ""));
                        productWarehouseEntity.setNum(num);
                        productWarehouseEntity.setOriNum(0D);
                        productWarehouseEntity.setWarehouseChecked(1);
                        productWarehouseEntity.setStockLowerLimit(0D);
                        productWarehouseEntity.setIsNotify(0);
                        productWarehouseEntity.setStockUpperLimit(0D);
                        if (Objects.equals(num, 0D)) {
                            productWarehouseEntity.setCost(0D);
                        } else {
                            productWarehouseEntity.setCost(Arith.div(productWarehouseCostMap.getOrDefault(warehouseKey, 0D), num));
                        }
                        productWarehouseEntity.setTotalCost(Arith.mul(productWarehouseEntity.getNum(),productWarehouseEntity.getCost()));
                        productWarehouseEntity.setWarehouseKey(warehouseKey);
                        insertList.add(productWarehouseEntity);
                    }
                    if (!insertList.isEmpty()) {
                        productWarehouseModel.insertBatch(insertList);
                    }
                }
                //sku
                List<UpdateDataEntity> updateList = new ArrayList<>();
                for (PaasFormDataEntityExt entityExt : productEntityExtList){
                    Double stock = entityExt.getData().getDouble(ProductEnum.STOCK.getAttr());
                    if (Objects.equals(stock, skuStockMap.getOrDefault(entityExt.getId(), 0D))) {
                        continue;
                    }
                    JSONObject json = new JSONObject();
                    json.put(ProductEnum.STOCK.getAttr(),skuStockMap.getOrDefault(entityExt.getId(),0D));
                    updateList.add(ExplainUtil.getUpdateData(entityExt.getId(),json,corpid));
                }
                if (!updateList.isEmpty()){
                    productModel.updateBatch(updateList,corpid);
                } else {
                    LOG.warn("no product update");
                }
            }
        }
        LOG.warn("fixAllStock over");
        return "can u speak php";
    }

    /**
     * 修复某个公司(某个产品)的所有库存信息:sku、productWarehouse
     * @param fixDataJobDTO
     * @param br
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/getMonthBeforeStock", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String getMonthBeforeStock(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (Objects.isNull(corpidList)) {
            corpidList = productModel.getCorpidList();
        }
        Long todayInt = DateTimeUtil.getTodayInt();
        Long monthBeforeInt = todayInt - 31*86400L;
        LOG.warn("fixAllStock begin");
        for (String corpid : corpidList) {
            Long idGte = 0L;
            Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID,corpid);
            param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
            List<WarehouseEntityExt> warehouseEntityExtList = warehouseModel.findEntitys(param);
            List<Long> warehouseIdList = new ArrayList<>();
            warehouseEntityExtList.forEach(item -> warehouseIdList.add(item.getId()));
            warehouseIdList.add(-1L);
            while (true) {
                param.clear();
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                if (Objects.nonNull(fixDataJobDTO.getDataIdList()) && !fixDataJobDTO.getDataIdList().isEmpty()) {
                    param.put("idIn",fixDataJobDTO.getDataIdList());
                }
                param.put("dataParentIdGte",0L);
                param.put("idGte",idGte);
                param.put("pageSize",1000);
                param.put("orderByStr","id asc");
                List<ProductEntityExt> productEntityExtList = productModel.findEntitys(param);
                if (productEntityExtList.isEmpty()) {
                    if (idGte <= 0L){
                        LOG.warn(JSONObject.toJSONString(param));
                        return "When I put a question mark, it is not that I have a problem, but I think you have a problem.";
                    }
                    break;
                }
                LOG.warn("idGte:" + idGte);
                idGte = productEntityExtList.get(productEntityExtList.size()-1).getId();
                List<Long> productIdList = new ArrayList<>();
                productEntityExtList.forEach(item -> productIdList.add(item.getId()));
                // 入库
                param.clear();
                param.put("corpid",corpid);
                param.put("productIdIn",productIdList);
                param.put("warehouseIdIn",warehouseIdList);
                param.put("del",0);
                List<InstockProductEntity> instockProductEntityList = instockProductModel.findEntitys(param);
                List<Long> idList = new ArrayList<>();
                if (!instockProductEntityList.isEmpty()) {
                    List<Long> instockIdList = new ArrayList<>();
                    instockProductEntityList.forEach(item -> instockIdList.add(item.getIntoWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", instockIdList);
                    filterMap.put("del", 0);
                    filterMap.put("greaterThanDate", monthBeforeInt);
                    idList = instockModel.findIds(filterMap);
                }
                Map<String,Double>  productWarehouseStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Double>  productWarehouseCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (InstockProductEntity entity : instockProductEntityList){
                    if (!idList.contains(entity.getIntoWarehouseId())){
                        continue;
                    }
                    // 分仓库存
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                    productWarehouseStock = Arith.add(productWarehouseStock, entity.getProductNum());
                    productWarehouseStockMap.put(key,productWarehouseStock);
                    // 分仓总成本
                    Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                    productWarehouseCost = Arith.add(productWarehouseCost, Arith.mul(entity.getProductNum(), entity.getCost()));
                    productWarehouseCostMap.put(key, productWarehouseCost);
                }
                //出库
                List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.findEntitys(param);
                idList = new ArrayList<>();
                if (!outstockProductEntityList.isEmpty()) {
                    List<Long> outstockIdList = new ArrayList<>();
                    outstockProductEntityList.forEach(item -> outstockIdList.add(item.getOutWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", outstockIdList);
                    filterMap.put("del", 0);
                    filterMap.put("greaterThanDate", monthBeforeInt);
                    idList = outstockModel.findIds(filterMap);
                }
                for (OutstockProductEntity entity : outstockProductEntityList){
                    if (!idList.contains(entity.getOutWarehouseId())){
                        continue;
                    }
                    // 分仓库存
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                    productWarehouseStock = Arith.sub(productWarehouseStock, entity.getProductNum());
                    productWarehouseStockMap.put(key, productWarehouseStock);
                    // 分仓总成本
                    Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                    productWarehouseCost = Arith.sub(productWarehouseCost, Arith.mul(entity.getProductNum(), entity.getCost()));
                    productWarehouseCostMap.put(key, productWarehouseCost);
                }
                param.clear();
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                param.put("greaterThanAddTime",monthBeforeInt);
                List<WarehouseOristockEntity> warehouseOristockEntityList = warehouseOristockModel.findEntitys(param);
                Map<Long,Long> oriWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                warehouseOristockEntityList.forEach(item -> oriWarehouseMap.put(item.getId().longValue(),item.getWarehouseId()));
                param.put("oriStockIdIn",oriWarehouseMap.keySet());
                param.put("productIdIn",productIdList);
                List<WarehouseOristockProductEntity> warehouseOristockProductEntityList = warehouseOristockProductModel.findEntitys(param);
                for (WarehouseOristockProductEntity warehouseOristockProductEntity : warehouseOristockProductEntityList) {
                    if (oriWarehouseMap.containsKey(warehouseOristockProductEntity.getOristockId().longValue())){
                        Long warehouseId = oriWarehouseMap.get(warehouseOristockProductEntity.getOristockId().longValue());
                        // 分仓库存
                        String key = warehouseOristockProductEntity.getProductId() + "_" + warehouseId;
                        Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                        productWarehouseStock = Arith.add(productWarehouseStock,warehouseOristockProductEntity.getOristockNum());
                        productWarehouseStockMap.put(key,productWarehouseStock);
                    }
                }
                if (!productWarehouseStockMap.keySet().isEmpty()) {
                    param.clear();
                    param.put(StringConstant.CORPID,corpid);
                    param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                    param.put("warehouseKeyIn", productWarehouseStockMap.keySet());
                    List<StockSurplusRecordEntity> stockSurplusRecordList = stockSurplusRecordModel.findEntitys(param);
                    for (StockSurplusRecordEntity stockSurplusRecordEntity : stockSurplusRecordList) {
                        stockSurplusRecordEntity.setRemainingCost(stockSurplusRecordEntity.getRemainingCost() - productWarehouseCostMap.getOrDefault(stockSurplusRecordEntity.getWarehouseKey(), 0D));
                        if (stockSurplusRecordEntity.getRemainingCost() <= 0.000001 && stockSurplusRecordEntity.getRemainingCost() > -0.000001) {
                            stockSurplusRecordEntity.setRemainingCost(0D);
                        }
                        stockSurplusRecordEntity.setRemainingStock(stockSurplusRecordEntity.getRemainingStock() - productWarehouseStockMap.get(stockSurplusRecordEntity.getWarehouseKey()));
                        if (stockSurplusRecordEntity.getRemainingStock() <= 0.000001 && stockSurplusRecordEntity.getRemainingStock() > -0.000001) {
                            stockSurplusRecordEntity.setRemainingStock(0D);
                            // 当结余库存为0时，强制设置结余成本为0 无奈之举
                            stockSurplusRecordEntity.setRemainingCost(0D);
                        }
                    }
                    stockSurplusRecordModel.updateBatch(stockSurplusRecordList, corpid);
                }
            }
        }
        LOG.warn("fixAllStock over");
        return "can u speak php";
    }

    /**
     * 修复某个公司(某个产品)的所有库存信息:sku、productWarehouse
     * @param fixDataJobDTO
     * @param br
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/insertMonthBeforeStockFlow", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String insertMonthBeforeStockFlow(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (Objects.isNull(corpidList)) {
            corpidList = productModel.getCorpidList();
        }
        Long todayInt = DateTimeUtil.getTodayInt();
        Long day = Objects.nonNull(fixDataJobDTO.getDay()) ? fixDataJobDTO.getDay() * 86400 : BusinessConstant.THIRTY_ONE_DAY;
        Long monthBeforeInt = todayInt - day;
        LOG.warn("insertMonthBeforeStockFlow begin");
        for (String corpid : corpidList) {
            // 保险起见，不管什么操作都先删除之前的流水
            stockFlowBillModel.deleteAllByCorpId(corpid);
            stockSurplusRecordModel.deleteAllByCorpId(corpid);
            // 插入当前分仓，往前推流水，后面会更新
            stockSurplusRecordModel.insertRecordsFromProductWarehouse(corpid, monthBeforeInt);
            Long idGte = 0L;
            Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID,corpid);
            param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
            List<WarehouseEntityExt> warehouseEntityExtList = warehouseModel.findEntitys(param);
            if (warehouseEntityExtList.isEmpty()) {
                continue;
            }
            List<Long> warehouseIdList = new ArrayList<>();
            warehouseEntityExtList.forEach(item -> warehouseIdList.add(item.getId()));
            while (true) {
                param.clear();
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                param.put("dataParentIdGte",0L);
                param.put("idGte",idGte);
                param.put("pageSize",1000);
                param.put("orderByStr","id asc");
                List<ProductEntityExt> productEntityExtList = productModel.findEntitys(param);
                if (productEntityExtList.isEmpty()) {
                    break;
                }
                idGte = productEntityExtList.get(productEntityExtList.size()-1).getId();
                List<Long> productIdList = new ArrayList<>();
                productEntityExtList.forEach(item -> productIdList.add(item.getId()));
                List<StockFlowBillEntity> flowBillEntityList = new ArrayList<>();
                // 入库
                param.clear();
                param.put("corpid",corpid);
                param.put("productIdIn",productIdList);
                param.put("warehouseIdIn",warehouseIdList);
                param.put("del",0);
                List<InstockProductEntity> instockProductEntityList = instockProductModel.findEntitys(param);
                List<Long> idList = new ArrayList<>();
                Map<Long, InstockEntityExt>  instockEntityExtMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (!instockProductEntityList.isEmpty()) {
                    List<Long> instockIdList = new ArrayList<>();
                    instockProductEntityList.forEach(item -> instockIdList.add(item.getIntoWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", instockIdList);
                    filterMap.put("del", 0);
                    filterMap.put("greaterThanDate", monthBeforeInt);
                    List<InstockEntityExt> instockEntityList = instockModel.findEntitys(filterMap);
                    instockEntityList.forEach(item -> {
                        idList.add(item.getId());
                        instockEntityExtMap.put(item.getId(), item);
                    });
                }
                Map<String,Double>  productWarehouseStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Double>  productWarehouseCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (InstockProductEntity entity : instockProductEntityList){
                    if (!idList.contains(entity.getIntoWarehouseId())){
                        continue;
                    }
                    // 分仓总库存
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                    productWarehouseStock = Arith.add(productWarehouseStock, entity.getProductNum());
                    productWarehouseStockMap.put(key,productWarehouseStock);
                    // 分仓总成本
                    Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                    productWarehouseCost = Arith.add(productWarehouseCost, Arith.mul(entity.getProductNum(), entity.getCost()));
                    productWarehouseCostMap.put(key, productWarehouseCost);
                    // 流水记录
                    InstockEntityExt instockEntityExt = instockEntityExtMap.get(entity.getIntoWarehouseId());
                    Long dateTime = instockEntityExt.getData().getLong(InstockEnum.TIME.getAttr());
                    Integer type = instockEntityExt.getData().getInteger(InstockEnum.TYPE.getAttr());
                    Integer businessType = InstockTypeEnum.getStockBusinessTypeByCode(type) == 0 ? XbbRefTypeEnum.OTHER_INSTOCK.getCode() : InstockTypeEnum.getStockBusinessTypeByCode(type);
                    Long businessId = null;
                    String businessName = null;
                    if (Objects.equals(businessType, XbbRefTypeEnum.REFUND_INSTOCK.getCode())) {
                        businessId = instockEntityExt.getData().getLong(RefundInstockEnum.CUSTOMER_ID.getAttr());
                        businessName = instockEntityExt.getData().getString(RefundInstockEnum.CUSTOMER_ID_LINKED_TEXT.getAttr());
                    } else if (Objects.equals(businessType, XbbRefTypeEnum.PURCHASE_INSTOCK.getCode())) {
                        businessId = instockEntityExt.getData().getLong(PurchaseInstockEnum.SUPPLIER_ID.getAttr());
                        businessName = instockEntityExt.getData().getString(PurchaseInstockEnum.SUPPLIER_ID_LINKED_TEXT.getAttr());
                    }
                    StockFlowBillEntity stockFlowBillEntity = new StockFlowBillEntity(corpid, entity.getWarehouseId(), entity.getIntoWarehouseId(), entity.getId(), StockTypeEnum.IN_STOCK.getCode(), entity.getProductId(), instockEntityExt.getSerialNo(), businessId, businessName, entity.getProductNum(), entity.getCost(), null, null, dateTime, businessType, key, entity.getMemo());
                    flowBillEntityList.add(stockFlowBillEntity);
                }
                //出库
                List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.findEntitys(param);
                idList.clear();
                Map<Long, OutstockEntityExt>  outstockEntityExtMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (!outstockProductEntityList.isEmpty()) {
                    List<Long> outstockIdList = new ArrayList<>();
                    outstockProductEntityList.forEach(item -> outstockIdList.add(item.getOutWarehouseId()));
                    Map<String, Object> filterMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    filterMap.put(StringConstant.CORPID, corpid);
                    filterMap.put("idIn", outstockIdList);
                    filterMap.put("del", 0);
                    filterMap.put("greaterThanDate", monthBeforeInt);
                    List<OutstockEntityExt> outstockEntityList = outstockModel.findEntitys(filterMap);
                    outstockEntityList.forEach(item -> {
                        idList.add(item.getId());
                        outstockEntityExtMap.put(item.getId(), item);
                    });
                }
                for (OutstockProductEntity entity : outstockProductEntityList){
                    if (!idList.contains(entity.getOutWarehouseId())){
                        continue;
                    }
                    // 分仓库存
                    String key = entity.getProductId() + "_" + entity.getWarehouseId();
                    Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                    productWarehouseStock = Arith.sub(productWarehouseStock, entity.getProductNum());
                    productWarehouseStockMap.put(key, productWarehouseStock);
                    // 分仓总成本
                    Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                    productWarehouseCost = Arith.sub(productWarehouseCost, Arith.mul(entity.getProductNum(), entity.getCost()));
                    productWarehouseCostMap.put(key, productWarehouseCost);
                    // 流水记录
                    OutstockEntityExt outstockEntityExt = outstockEntityExtMap.get(entity.getOutWarehouseId());
                    Long dateTime = outstockEntityExt.getData().getLong(OutstockEnum.TIME.getAttr());
                    Integer type = outstockEntityExt.getData().getInteger(OutstockEnum.TYPE.getAttr());
                    Integer businessType = OutstockTypeEnum.getStockBusinessTypeByCode(type) == 0 ? XbbRefTypeEnum.OTHER_OUTSTOCK.getCode() : OutstockTypeEnum.getStockBusinessTypeByCode(type);
                    Long businessId = null;
                    String businessName = null;
                    if (Objects.equals(businessType, XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                        businessId = outstockEntityExt.getData().getLong(ContractOutstockEnum.LINK_CUSTOMER.getAttr());
                        businessName = outstockEntityExt.getData().getString(ContractOutstockEnum.LINK_CUSTOMER_HIDE.getAttr());
                    } else if (Objects.equals(businessType, XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())) {
                        businessId = outstockEntityExt.getData().getLong(ReturnedPurchaseOutstockEnum.LINK_SUPPLIER.getAttr());
                        businessName = outstockEntityExt.getData().getString(ReturnedPurchaseOutstockEnum.LINK_SUPPLIER_HIDE.getAttr());
                    } else if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER_OUTSTOCK.getCode())) {
                        businessId = outstockEntityExt.getData().getLong(WorkOrderOutstockEnum.LINK_CUSTOMER.getAttr());
                        businessName = outstockEntityExt.getData().getString(WorkOrderOutstockEnum.LINK_CUSTOMER_HIDE.getAttr());
                    }
                    StockFlowBillEntity stockFlowBillEntity = new StockFlowBillEntity(corpid, entity.getWarehouseId(), entity.getOutWarehouseId(), entity.getId(), StockTypeEnum.OUT_STOCK.getCode(), entity.getProductId(), outstockEntityExt.getSerialNo(), businessId, businessName, entity.getProductNum(), entity.getCost(), null, null, dateTime, businessType, key, entity.getMemo());
                    flowBillEntityList.add(stockFlowBillEntity);
                }
                param.clear();
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                param.put("warehouseIdIn", warehouseIdList);
                param.put("greaterThanAddTime",monthBeforeInt);
                List<WarehouseOristockEntity> warehouseOristockEntityList = warehouseOristockModel.findEntitys(param);
                Map<Long,WarehouseOristockEntity> oriWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                warehouseOristockEntityList.forEach(item -> oriWarehouseMap.put(item.getId().longValue(),item));
                param.put("oriStockIdIn",oriWarehouseMap.keySet());
                param.put("productIdIn",productIdList);
                List<WarehouseOristockProductEntity> warehouseOristockProductEntityList = warehouseOristockProductModel.findEntitys(param);
                for (WarehouseOristockProductEntity warehouseOristockProductEntity : warehouseOristockProductEntityList) {
                    if (oriWarehouseMap.containsKey(warehouseOristockProductEntity.getOristockId().longValue())){
                        WarehouseOristockEntity warehouseOristockEntity = oriWarehouseMap.get(warehouseOristockProductEntity.getOristockId().longValue());
                        Long warehouseId = warehouseOristockEntity.getWarehouseId();
                        // 分仓库存
                        String key = warehouseOristockProductEntity.getProductId() + "_" + warehouseId;
                        Double productWarehouseStock = productWarehouseStockMap.getOrDefault(key,0D);
                        productWarehouseStock = Arith.add(productWarehouseStock,warehouseOristockProductEntity.getOristockNum());
                        productWarehouseStockMap.put(key,productWarehouseStock);
                        // 分仓总成本
                        Double productWarehouseCost = productWarehouseCostMap.getOrDefault(key,0D);
                        Double cost = warehouseOristockProductEntity.getCost() == null ? 0D : warehouseOristockProductEntity.getCost();
                        productWarehouseCost = Arith.add(productWarehouseCost, Arith.mul(warehouseOristockProductEntity.getOristockNum(), cost));
                        productWarehouseCostMap.put(key, productWarehouseCost);
                        // 流水记录
                        Long dateTime = DateTimeUtil.getTodayInt(warehouseOristockEntity.getAddTime());
                        StockFlowBillEntity stockFlowBillEntity = new StockFlowBillEntity(corpid, warehouseId, warehouseOristockProductEntity.getOristockId().longValue(), warehouseOristockProductEntity.getId(), StockTypeEnum.ORI_STOCK.getCode(), warehouseOristockProductEntity.getProductId(), warehouseOristockEntity.getSerialNo(), null, null, warehouseOristockProductEntity.getOristockNum(), cost, null, null, dateTime, XbbRefTypeEnum.ORI_STOCK.getCode(), key, warehouseOristockProductEntity.getMemo());
                        flowBillEntityList.add(stockFlowBillEntity);
                    }
                }
                List<StockFlowBillEntity> sortedInsertList = flowBillEntityList.stream().sorted(Comparator.comparing(StockFlowBillEntity::getDate)).collect(Collectors.toList());
                Map<String, List<StockFlowBillEntity>> sortedInsertMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                sortedInsertList.forEach(item -> {
                    List<StockFlowBillEntity> sortedList = sortedInsertMap.getOrDefault(item.getWarehouseKey(), new ArrayList<>());
                    sortedList.add(item);
                    sortedInsertMap.put(item.getWarehouseKey(), sortedList);
                });
                if (!productWarehouseStockMap.keySet().isEmpty()) {
                    param.clear();
                    param.put(StringConstant.CORPID,corpid);
                    param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                    param.put("date",monthBeforeInt);
                    param.put("warehouseKeyIn", productWarehouseStockMap.keySet());
                    List<StockSurplusRecordEntity> stockSurplusRecordList = stockSurplusRecordModel.findEntitys(param);
                    for (StockSurplusRecordEntity stockSurplusRecordEntity : stockSurplusRecordList) {
                        String warehouseKey = stockSurplusRecordEntity.getWarehouseKey();
                        if (sortedInsertMap.containsKey(warehouseKey)) {
                            Double remainCost = stockSurplusRecordEntity.getRemainingCost();
                            Double remainStock = stockSurplusRecordEntity.getRemainingStock();
                            List<StockFlowBillEntity> billEntityList = sortedInsertMap.get(warehouseKey);
                            sortedInsertMap.remove(warehouseKey);
                            for (int i = billEntityList.size() - 1; i >= 0; i--) {
                                StockFlowBillEntity stockFlowBillEntity = billEntityList.get(i);
                                if (i == billEntityList.size() - 1) {
                                    // 最后一次记录的结存等于当前结存
                                    stockFlowBillEntity.setRemainingCost(remainCost);
                                    stockFlowBillEntity.setRemainingStock(remainStock);
                                } else {
                                    // 前一次的结存等于后一次结存 - 后一次出入库数量和总成本
                                    StockFlowBillEntity lastStockFlowBillEntity = billEntityList.get(i + 1);
                                    Double num = lastStockFlowBillEntity.getNum();
                                    Double productCost = lastStockFlowBillEntity.getProductCost();
                                    Integer stockType = lastStockFlowBillEntity.getStockType();
                                    if (stockType == 1 || stockType == 3) {
                                        remainStock = Arith.sub(remainStock, num);
                                        remainCost = Arith.sub(remainCost, Arith.mul(num, productCost));
                                        stockFlowBillEntity.setRemainingCost(remainCost);
                                        stockFlowBillEntity.setRemainingStock(remainStock);
                                    } else if (stockType == 2) {
                                        remainStock = Arith.add(remainStock, num);
                                        remainCost = Arith.add(remainCost, Arith.mul(num, productCost));
                                        stockFlowBillEntity.setRemainingCost(remainCost);
                                        stockFlowBillEntity.setRemainingStock(remainStock);
                                    }
                                    if (stockFlowBillEntity.getRemainingCost() <= 0.000001 && stockFlowBillEntity.getRemainingCost() > -0.000001) {
                                        stockFlowBillEntity.setRemainingCost(0D);
                                        remainCost = 0D;
                                    }
                                    if (stockFlowBillEntity.getRemainingStock() <= 0.000001 && stockFlowBillEntity.getRemainingStock() > -0.000001) {
                                        stockFlowBillEntity.setRemainingStock(0D);
                                        remainStock = 0D;
                                    }
                                }
                            }
                        }
                        stockSurplusRecordEntity.setRemainingCost(stockSurplusRecordEntity.getRemainingCost() - productWarehouseCostMap.getOrDefault(warehouseKey, 0D));
                        if (stockSurplusRecordEntity.getRemainingCost() <= 0.000001 && stockSurplusRecordEntity.getRemainingCost() > -0.000001) {
                            stockSurplusRecordEntity.setRemainingCost(0D);
                        }
                        stockSurplusRecordEntity.setRemainingStock(stockSurplusRecordEntity.getRemainingStock() - productWarehouseStockMap.get(warehouseKey));
                        if (stockSurplusRecordEntity.getRemainingStock() <= 0.000001 && stockSurplusRecordEntity.getRemainingStock() > -0.000001) {
                            stockSurplusRecordEntity.setRemainingStock(0D);
                        }
                    }
                    // 解绑的流水也会生成
                    if (!sortedInsertMap.isEmpty()) {
                        for (List<StockFlowBillEntity> billEntityList : sortedInsertMap.values()) {
                            Double remainCost = 0D;
                            Double remainStock = 0D;
                            for (int i = billEntityList.size() - 1; i >= 0; i--) {
                                StockFlowBillEntity stockFlowBillEntity = billEntityList.get(i);
                                if (i == billEntityList.size() - 1) {
                                    // 最后一次记录的结存等于当前结存
                                    stockFlowBillEntity.setRemainingCost(remainCost);
                                    stockFlowBillEntity.setRemainingStock(remainStock);
                                } else {
                                    // 前一次的结存等于后一次结存 - 后一次出入库数量和总成本
                                    StockFlowBillEntity lastStockFlowBillEntity = billEntityList.get(i + 1);
                                    Double num = lastStockFlowBillEntity.getNum();
                                    Double productCost = lastStockFlowBillEntity.getProductCost();
                                    Integer stockType = lastStockFlowBillEntity.getStockType();
                                    if (stockType == 1 || stockType == 3) {
                                        remainStock = Arith.sub(remainStock, num);
                                        remainCost = Arith.sub(remainCost, Arith.mul(num, productCost));
                                        stockFlowBillEntity.setRemainingCost(remainCost);
                                        stockFlowBillEntity.setRemainingStock(remainStock);
                                    } else if (stockType == 2) {
                                        remainStock = Arith.add(remainStock, num);
                                        remainCost = Arith.add(remainCost, Arith.mul(num, productCost));
                                        stockFlowBillEntity.setRemainingCost(remainCost);
                                        stockFlowBillEntity.setRemainingStock(remainStock);
                                    }
                                    if (stockFlowBillEntity.getRemainingCost() <= 0.000001 && stockFlowBillEntity.getRemainingCost() > -0.000001) {
                                        stockFlowBillEntity.setRemainingCost(0D);
                                        remainCost = 0D;
                                    }
                                    if (stockFlowBillEntity.getRemainingStock() <= 0.000001 && stockFlowBillEntity.getRemainingStock() > -0.000001) {
                                        stockFlowBillEntity.setRemainingStock(0D);
                                        remainStock = 0D;
                                    }
                                }
                            }
                        }
                    }
                    if (!stockSurplusRecordList.isEmpty()) {
                        int pageSize = 1000;
                        int totalCount = sortedInsertList.size();
                        int start = 0;
                        while (true) {
                            if ((start + 1) * pageSize >= totalCount) {
                                stockFlowBillModel.insertBatch(sortedInsertList.subList(start * pageSize,totalCount));
                                break;
                            } else {
                                stockFlowBillModel.insertBatch(sortedInsertList.subList(start * pageSize,(start + 1) * pageSize));
                            }
                            start++;
                        }
                        stockSurplusRecordModel.updateBatch(stockSurplusRecordList, corpid);
                    }
                }
            }
        }
        LOG.warn("insertMonthBeforeStockFlow over");
        return "can u speak chinese";
    }

    /**
     * 校验流水信息是否正确:sku、productWarehouse
     * @param fixDataJobDTO
     * @param br
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/checkStockFlow", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String checkStockFlow(@RequestBody @Valid FixDataJobDTO fixDataJobDTO, BindingResult br) throws Exception {
        if (!proBaseConfig.getXbbCode().equals(fixDataJobDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006);
        }
        List<String> corpidList = fixDataJobDTO.getCorpidList();
        if (Objects.isNull(corpidList)) {
            corpidList = productModel.getCorpidList();
        }
        Long todayInt = DateTimeUtil.getTodayInt();
        Long monthBeforeInt = todayInt - BusinessConstant.THIRTY_ONE_DAY;
        LOG.warn("checkStockFlow begin");
        for (String corpid : corpidList) {
        }
        LOG.warn("checkStockFlow over");
        return "can u speak chinese";
    }
}
